/*
 * Copyright  bocmbci
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { KeyCode } from '@ohos.multimodalInput.keyCode';
import { CallbackContext } from './CallbackContext';
import { CordovaPlugin } from './CordovaPlugin';
import { PluginResult, PluginResultStatus } from './PluginResult';

export class CoreAndroid extends CordovaPlugin{
  messageChannel: CallbackContext;
  pendingResume: PluginResult;
  pendingPause: PluginResult;
  messageChannelLock = new Object();

  /**
   * 发送一个事件到Javascript端。
   *
   * @param action 要触发的事件名称
   */
  fireJavascriptEvent(action: string) {
    this.sendEventMessage(action);
  }

  /**
   * Executes the request and returns PluginResult.
   *
   * @param action            The action to execute.
   * @param args              JSONArray of arguments for the plugin.
   * @param callbackContext   The callback context from which we were invoked.
   * @return                  A PluginResult object with a status and message.
   */
  execute(action: string, args: string, callbackContext: CallbackContext): boolean {
    let status = PluginResultStatus.OK;
    let result = "";

    try {
      let argsJson = JSON.parse(args)

      if (action === "clearCache") {
        this.clearCache();
      } else if (action === "show") {
        // This gets called from JavaScript onCordovaReady to show the webview.
        // I recommend we change the name of the Message as spinner/stop is not
        // indicative of what this actually does (shows the webview).
        this.cordovaWebViewService.getPluginManager().postMessage("spinner", "stop");
      } else if (action === "loadUrl") {
        this.loadUrl(argsJson[0], argsJson[1]);
      } else if (action === "cancelLoadUrl") {
        //this.cancelLoadUrl();
        this.cordovaWebViewService.getViewController().stop();
      } else if (action === "clearHistory") {
        this.clearHistory();
      } else if (action === "backHistory") {
        this.backHistory();
      } else if (action === "overrideButton") {
        this.overrideButton(args[0], argsJson.getBoolean(1));
      } else if (action === "overrideBackbutton") {
        this.overrideBackbutton(argsJson.getBoolean(0));
      } else if (action === "exitApp") {
        this.exitApp();
      } else if (action === "messageChannel") {
        this.messageChannel = callbackContext;
        if (this.pendingPause != null) {
          this.sendEventMessage(this.pendingPause.getStrMessage());
          this.pendingPause = null;
        }
        if (this.pendingResume != null) {
          this.sendEventMessage(this.pendingResume.getStrMessage());
          this.pendingResume = null;
        }
        return true;
      }
      callbackContext.sendPluginResult(new PluginResult(status, result));
      return true;
    } catch (e) {
      callbackContext.sendPluginResult(new PluginResult(PluginResultStatus.JSON_EXCEPTION, "json_exception"));
      return false;
    }
  }

  /**
   * Clear the resource cache.
   */
  clearCache(){
    this.cordovaWebViewService.clearCache();
  }

  loadUrl(url: string, props: any){
    console.log("App", `App.loadUrl(${url}, ${props})`);
    let wait = 0;
    let openExternal = false;
    let clearHistory = false;

    // If there are properties, then set them on the Activity
    const params: Map<string, any> = new Map();
    if (props != null) {
      const keys: Array<any> = props.names();
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i];
        if (key === "wait") {
          wait = props.getInt(key);
        } else if (key.toLowerCase() === "openexternal") {
          openExternal = props.getBoolean(key);
        } else if (key.toLowerCase() === "clearhistory") {
          clearHistory = props.getBoolean(key);
        } else {
          const value = props.get(key);
          if (value === null) {}
          else if (typeof value === "string") {
            params[key] = value as string;
          } else if (typeof value === "boolean") {
            params[key] = value as boolean;
          } else if (typeof value === "number") {
            params[key] = value as number;
          }
        }
      }
    }
    // If wait property, then delay loading
    if (wait > 0) {
      new Promise((resolve) => setTimeout(resolve, wait)).then(data =>{
        this.cordovaWebViewService.showWebPage(url, openExternal, clearHistory, params);
      });
      return;
    }
    this.cordovaWebViewService.showWebPage(url, openExternal, clearHistory, params);
  }

  /**
   * Clear page history for the app.
   */
  public clearHistory(): void {
    this.cordovaWebViewService.clearHistory();
  }

  /**
   * Go to previous page displayed.
   * This is the same as pressing the backbutton on Android device.
   */
  public backHistory(): void {
    this.cordovaWebViewService.backHistory();
  }

  /**
   * Override the default behavior of the Android back button.
   * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
   *
   * @param override  T=override, F=cancel override
   */
  overrideBackbutton(value: boolean) {
    this.cordovaWebViewService.setButtonPlumbedToJs(KeyCode.KEYCODE_BACK, value)
  }

  /**
   * Override the default behavior of the Android volume buttons.
   * If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired.
   *
   * @param button        volumeup, volumedown
   * @param override      T=override, F=cancel override
   */
   private overrideButton(button: string, isOverride: boolean): void {
    if (button === "volumeup") {
      this.cordovaWebViewService.setButtonPlumbedToJs(KeyCode.KEYCODE_VOLUME_UP, isOverride);
    }
    else if (button === "volumedown") {
      this.cordovaWebViewService.setButtonPlumbedToJs(KeyCode.KEYCODE_VOLUME_DOWN, isOverride);
    }
    else if (button === "menubutton") {
      this.cordovaWebViewService.setButtonPlumbedToJs(KeyCode.KEYCODE_MENU, isOverride);
    }
  }

  /**
   * Return whether the Android back button is overridden by the user.
   *
   * @return boolean
   */
  public isBackbuttonOverridden(): boolean {
    return this.cordovaWebViewService.isButtonPlumbedToJs(KeyCode.KEYCODE_BACK);
  }

  /**
   * Exit the Android application.
   */
  public exitApp(): void {
    this.cordovaWebViewService.getPluginManager().postMessage("exit", null);
  }

  private sendEventMessage(action: string) {
    const obj = { };
    obj["action"] = action;
    const result = new PluginResult(PluginResultStatus.OK, obj);

    if (!this.messageChannel) {
      if (action === "pause") {
        this.pendingPause = result;
      } else if (action === "resume") {
        // When starting normally onPause then onResume is called
        this.pendingPause = null;
      }
    } else {
      this.sendEventMessage(action);
    }
  }

  /**
   * Used to send the resume event in the case that the Activity is destroyed by the OS
   *
   * @param resumeEvent PluginResult containing the payload for the resume event to be fired
   */
  public sendResumeEvent(resumeEvent: PluginResult){
    // This operation must be synchronized because plugin results that trigger resume
    // events can be processed asynchronously
    const messageChannelLock = {};
    if (this.messageChannel != null) {
      this.sendEventMessage(resumeEvent ? resumeEvent.getStrMessage() : "");
    } else {
      // Might get called before the page loads, so we need to store it until the
      // messageChannel gets created
      this.pendingResume = resumeEvent;
    }
  }

}